package gu.sql2java.excel;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Strings.nullToEmpty;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.ss.usermodel.Workbook;

import com.google.common.collect.ImmutableSet;

/**
 * @author guyadong
 * @since 3.13.0
 *
 */
public abstract class BaseExcelWriter {
    
    private static final String FORMAT_SUFFIX_XLSX = ".xlsx";
    private static final String FORMAT_SUFFIX_CSV = ".csv";
    private static final String DEFAULT_FORMAT_SUFFIX = FORMAT_SUFFIX_XLSX;
    private static final ImmutableSet<String> supportedSuffixs = 
            ImmutableSet.of(FORMAT_SUFFIX_XLSX,FORMAT_SUFFIX_CSV);
	/**
	 * 将输入的数据记录生成输出到Excel的 {@link Workbook}
	 * @throws IOException 
	 */
	protected abstract void write() throws IOException;
	/**
	 * 将输入的数据记录生成输出到{@link OutputStream}
	 * @param outputStream
	 * @throws IOException
	 * @since 3.15.4
	 */
	protected abstract void write(OutputStream outputStream) throws IOException;
	/**
	 * 返回当前的{@link Workbook}实例
	 */
	protected abstract Workbook getWorkbook();
	/**
	 * 生成Excel格式(.xlsx)数据到输出流
	 * @param outputStream
	 * @throws IOException
	 * @see #generate(OutputStream, String, String)
	 */
	public void generate(OutputStream outputStream) throws IOException {
	    generate(outputStream,null, null);
	}
	/**
	 * 导出数据到输出流
	 * @param outputStream
	 * @param formatSuffix 输出格式,为{@code null}为默认值{@code .xlsx},支持的值:{@code .xlsx,.csv}
	 * @param zipEntryName 不为空时输出为ZIP,指定ZIP包内的文件名
	 * @throws IOException
	 * @see #write()
	 * @see #write(OutputStream)
	 * @since 3.15.4
	 */
	public void generate(OutputStream outputStream,String formatSuffix, String zipEntryName) throws IOException {
	    checkArgument(null != outputStream, "outputStream is null");
	    formatSuffix = firstNonNull(formatSuffix, DEFAULT_FORMAT_SUFFIX);
	    zipEntryName = nullToEmpty(zipEntryName).trim();
	    
	    if(!zipEntryName.isEmpty()){
	        ZipOutputStream zos = new ZipOutputStream(outputStream);
            zos.putNextEntry(new ZipEntry(zipEntryName));
            outputStream = zos;
	    }
	    try {
	        switch (formatSuffix) {
	            case FORMAT_SUFFIX_XLSX:
	                write();
	                getWorkbook().write(outputStream);
	                getWorkbook().close();
	                break;
	            case FORMAT_SUFFIX_CSV:
	            {
	                this.write(outputStream);
	                break;
	            }
	            default:
	                throw new IllegalArgumentException(String.format(
	                        "INVALID suffix %s, available %s",formatSuffix, supportedSuffixs));
	        }
        } finally {
            if(outputStream instanceof ZipOutputStream){
                ((ZipOutputStream)outputStream).closeEntry();
                outputStream.close();
            }
        }
	}
	/**
	 * 生成Excel格式数据到指定的文件
	 * @param outputStream
	 * @throws IOException
	 */
	public void generate(File file) throws IOException {
		try(FileOutputStream outputStream = new FileOutputStream(checkNotNull(file,"file is null"))) {
			generate(outputStream);
		}
	}
	/**
	 * 生成Excel格式数据到指定的文件
	 * @param outputStream
	 * @throws IOException
	 */
	public void generate(String file) throws IOException {
		try(FileOutputStream outputStream = new FileOutputStream(checkNotNull(file,"file is null"))) {
			generate(outputStream);
		}
	}
	/**
	 * 生成Excel格式(.xlsx)数据到HTTP Response
	 * @param response
	 * @throws IOException
	 * @see {@link #generate(HttpServletResponse, String, String)}
	 */
	public void generate(HttpServletResponse response) throws IOException {
	    generate(response,null, null);
	}
	/**
	 * 导出数据到HTTP Response
	 * @param response
	 * @param formatSuffix 输出格式,为{@code null}为默认值{@code .xlsx},支持的值:{@code .xlsx,.csv}
	 * @param zipEntryName 输出为ZIP时指定ZIP包内的文件名
	 * @throws IOException
	 * @since 3.15.4
	 */
	public void generate(HttpServletResponse response,String formatSuffix, String zipEntryName) throws IOException {
	    ServletOutputStream outputStream = response.getOutputStream();
	    generate(outputStream,formatSuffix, zipEntryName);
	    outputStream.close();
	}
}
